/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.ibatis.extension.plugins;

import com.je.ibatis.extension.plugins.inner.InnerInterceptor;
import com.je.ibatis.extension.plugins.inner.PagableInnerInterceptor;
import com.je.ibatis.extension.plugins.inner.TenantInnerInterceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * 封装统一ibatis插件封装，此插件为内部插件对外的统一门面入口
 */
@Intercepts(
        {
                @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
        }
)
public class JeIbatisInterceptor implements Interceptor {

    private static final Log LOGGER = LogFactory.getLog(JeIbatisInterceptor.class);

    private List<InnerInterceptor> innerInterceptorList = new ArrayList<>();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        if(target instanceof Executor){
            return invocation.proceed();
        }
        final StatementHandler sh = (StatementHandler) target;
        Object[] args = invocation.getArgs();
        Connection connection = (Connection) args[0];
        Integer transactionTimeout = (Integer) args[1];
        if (innerInterceptorList != null && !innerInterceptorList.isEmpty()) {
            for (InnerInterceptor eachInterceptor : innerInterceptorList) {
                if (eachInterceptor.isEnable()) {
                    eachInterceptor.beforePrepare(sh, connection, transactionTimeout);
                }
            }
        }

        if(LOGGER.isInfoEnabled()){
            LOGGER.info(sh.getBoundSql().getSql());
        }

        return invocation.proceed();
    }

    /**
     * 添加
     *
     * @param innerInterceptor
     */
    public void add(InnerInterceptor innerInterceptor) {
        innerInterceptorList.add(innerInterceptor);
    }

    /**
     * 添加所有
     *
     * @param newInnerInterceptorList
     */
    public void addAll(List<InnerInterceptor> newInnerInterceptorList) {
        innerInterceptorList.addAll(newInnerInterceptorList);
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {
        InnerInterceptor pagableInnerInterceptor = new PagableInnerInterceptor();
        pagableInnerInterceptor.setProperties(properties);
        InnerInterceptor tenantInnerInterceptor = new TenantInnerInterceptor();
        tenantInnerInterceptor.setProperties(properties);

        add(tenantInnerInterceptor);
        add(pagableInnerInterceptor);
//        add(new BlockAttackInnerInterceptor());

    }

}
